package eu.common.toolkits;

import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.HashMap;
import java.util.Map;

/**
 * 反射工具
 * @author WZZ
 *
 */
public class ReflectUtil {

	/**
	 * 通过getter获取所有的成员变量, 不包括父类
	 * @param object
	 * @return
	 */
	public static Map<String, Object> getFields(Object object) {
		Map<String, Object> ret = new HashMap<String, Object>();
        for (Field field : object.getClass().getDeclaredFields()) {
        	ret.put(field.getName(), getVal(object, field.getName()));
        }
		return ret;
	}
	
	/**
	 * 调用方法
	 * @param clazz
	 * @param object
	 * @param methodName
	 * @param parameterTypes
	 * @param parameters
	 * @return
	 */
	public static Object invokeMethod(Class<?> clazz, Object object, String methodName,
			Class<?>[] parameterTypes, Object[] parameters){
		Method method = null;
		if (clazz != null) {
			method = getStaticMethod(clazz, methodName, parameterTypes);
		} else {
			method = getDeclaredMethod(object, methodName, parameterTypes);
		}
		if (method == null) {
			throw new IllegalArgumentException("Could not find method ["
					+ methodName + "] on target [" + object + "]");
		}
		method.setAccessible(true);
		try {
			return method.invoke(object, parameters);
		} catch (IllegalAccessException e) {
		} catch (IllegalArgumentException e) {
			throw new IllegalArgumentException("Could not find method ["
					+ methodName + "] on target [" + object + "]");
		} catch (InvocationTargetException e) {
			throw new IllegalArgumentException("Could not find method ["
					+ methodName + "] on target [" + object + "]");
		}

		return null;
	}

	/**
	 * 直接设置属性的值
	 * @param object
	 * @param fieldName
	 * @param value
	 */
	public static void setFieldValue(Object object, String fieldName,
			Object value) {
		Field field = getDeclaredField(object, fieldName);

		if (field == null)
			throw new IllegalArgumentException("Could not find field ["
					+ fieldName + "] on target [" + object + "]");

		makeAccessible(field);

		try {
			field.set(object, value);
		} catch (IllegalAccessException e) {
			e.printStackTrace();
		}
	}

	/**
	 * 直接获取属性的值
	 * @param object
	 * @param fieldName
	 * @return
	 */
	public static Object getFieldValue(Object object, String fieldName) {
		Field field = getDeclaredField(object, fieldName);
		if (field == null)
			throw new IllegalArgumentException("Could not find field ["
					+ fieldName + "] on target [" + object + "]");
		makeAccessible(field);
		Object result = null;
		try {
			result = field.get(object);
		} catch (IllegalAccessException e) {
			e.printStackTrace();
		}
		return result;
	}
	
	/**
	 * 通过getter获取属性的值
	 * @param obj
	 * @param fieldName
	 * @return
	 */
	public static Object getVal(Object obj, String fieldName) {
		return operate(obj, fieldName, null, "get");
	}

	/**
	 * 通过setter设置属性的值
	 * @param obj
	 * @param fieldName
	 * @param fieldVal
	 */
	public static void setVal(Object obj, String fieldName, Object fieldVal) {
		operate(obj, fieldName, fieldVal, "set");
	}
	
	/**
	 * 
	 * @param obj
	 * @param fieldName
	 * @param fieldVal
	 * @param type
	 * @return
	 */
	private static Object operate(Object obj, String fieldName,
			Object fieldVal, String type) {
		Object ret = null;
			// 获得对象类型
			Class<? extends Object> classType = obj.getClass();
			try {
					String firstLetter = fieldName.substring(0, 1)
							.toUpperCase(); // 获得和属性对应的getXXX()方法的名字
					if ("set".equals(type)) {
						String setMethodName = "set" + firstLetter
								+ fieldName.substring(1); // 获得和属性对应的getXXX()方法
						Method setMethod = classType.getMethod(setMethodName,
								new Class[] {fieldVal.getClass()}); // 调用原对象的getXXX()方法
						ret = setMethod.invoke(obj, new Object[] { fieldVal });
					}
					if ("get".equals(type)) {
						String getMethodName = "get" + firstLetter
								+ fieldName.substring(1); // 获得和属性对应的setXXX()方法的名字
						Method getMethod = classType.getMethod(getMethodName,
								new Class[] {});
						ret = getMethod.invoke(obj, new Object[] {});
					}
			} catch (Exception e) {
				e.printStackTrace();
			}
			return ret;
	}

	private static Method getDeclaredMethod(Object object, String methodName,
			Class<?>[] parameterTypes) {
		for (Class<?> superClass = object.getClass(); superClass != Object.class; superClass = superClass
				.getSuperclass()) {
			try {
				return superClass.getDeclaredMethod(methodName, parameterTypes);
			} catch (NoSuchMethodException e) {
				// Method 不在当前类定义, 继续向上转型
			}
		}

		return null;
	}

	private static Method getStaticMethod(Class<?> clazz, String methodName, Class<?>[] parameterTypes) {
		for (Class<?> superClass = clazz; superClass != Object.class; superClass = superClass
				.getSuperclass()) {
			try {
				return superClass.getDeclaredMethod(methodName, parameterTypes);
			} catch (NoSuchMethodException e) {
				// Method 不在当前类定义, 继续向上转型
			}
		}

		return null;
	}
	private static void makeAccessible(Field field) {
		if (!Modifier.isPublic(field.getModifiers())) {
			field.setAccessible(true);
		}
	}

	/**
	 * 
	 * @param object
	 * @param filedName
	 * @return
	 */
	private static Field getDeclaredField(Object object, String filedName) {
		for (Class<?> superClass = object.getClass(); superClass != Object.class; superClass = superClass
				.getSuperclass()) {
			try {
				return superClass.getDeclaredField(filedName);
			} catch (NoSuchFieldException e) {
				// Field 不在当前类定义, 继续向上转型
			}
		}
		return null;
	}


}
